package cn.huaqingcheng.tool.core;

import org.jetbrains.annotations.Contract;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;

/**
 * 随机数工具
 *
 * @see RandomGenerator
 * @see Random
 * @see ThreadLocalRandom
 * @see SecureRandom
 * @see RandomGeneratorFactory
 */
@SuppressWarnings({"SpellCheckingInspection", "unused"})
public interface RandomTool {

    /**
     * 小写字母
     */
    char[] b = "abcdefghijklmnopqrstuvwxyz".toCharArray();

    /**
     * 大写字母
     */
    char[] B = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();

    /**
     * 大写和小写字母
     */
    char[] bB = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();

    /**
     * 纯数字
     */
    char[] N = "0123456789".toCharArray();

    /**
     * 字母和数字
     */
    char[] bBN = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();

    /**
     * 随机固定长度的字符串, 并使用自定义字符池
     *
     * @param len  字符串长度
     * @param pool 自定义字符池 (串中每一个字符) {@link String#toCharArray()}
     * @see #b
     * @see #B
     * @see #bB
     * @see #N
     * @see #bBN
     */
    @Contract(pure = true)
    static String str(int len, String pool) {
        return str(len, pool.toCharArray());
    }

    /**
     * 随机固定长度的字符串, 并使用自定义字符池
     *
     * @param len  字符串长度
     * @param pool 自定义字符池
     */
    @Contract(pure = true)
    static String str(int len, char[] pool) {
        if (len <= 0) {
            return StrTool.EMPTY;
        }
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            int index = gen().nextInt(0, pool.length);
            sb.append(pool[index]);
        }
        return sb.toString();
    }

    /**
     * 随机数生成器, 禁止保存返回值 (以免造成意外跨线程访问)
     */
    private static RandomGenerator gen() {
        return ThreadLocalRandom.current();
    }

    /**
     * 随机多个字符串
     *
     * @param len  字符串长度
     * @param size 数量
     */
    @Contract(pure = true)
    static String[] strArr(int len, int size) {
        String[] arr = new String[size];
        Arrays.setAll(arr, i -> str(len));

        return arr;
    }

    /**
     * 随机固定长度的字符串, 使用所有字母和数字
     *
     * @param len 字符串长度
     */
    @Contract(pure = true)
    static String str(int len) {
        return str(len, bBN);
    }

    /**
     * 随机多个字符串
     *
     * @param len  字符串长度
     * @param size 数量
     * @param pool 自定义字符池
     */
    @Contract(pure = true)
    static String[] strArr(int len, int size, String pool) {
        return strArr(len, size, pool.toCharArray());
    }

    /**
     * 随机多个字符串
     *
     * @param len  字符串长度
     * @param size 数量
     * @param pool 字符池
     */
    @Contract(pure = true)
    static String[] strArr(int len, int size, char[] pool) {
        String[] arr = new String[size];
        Arrays.setAll(arr, i -> str(len, pool));

        return arr;
    }

    /**
     * 随机多个字符串
     *
     * @param len  字符串长度
     * @param size 数量
     */
    @Contract(pure = true)
    static List<String> strList(int len, int size) {
        List<String> list = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
            list.set(i, str(len));
        }

        return list;
    }

    /**
     * 随机多个字符串
     *
     * @param len  字符串长度
     * @param size 数量
     * @param pool 自定义字符池
     */
    @Contract(pure = true)
    static List<String> strList(int len, int size, String pool) {
        return strList(len, size, pool.toCharArray());
    }

    /**
     * 随机多个字符串
     *
     * @param len  字符串长度
     * @param size 数量
     * @param pool 自定义字符池
     */
    @Contract(pure = true)
    static List<String> strList(int len, int size, char[] pool) {
        List<String> list = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
            list.set(i, str(len, pool));
        }
        return list;
    }

    /**
     * 随机数字
     *
     * @param start 开始范围, 包含
     * @param end   结束范围, 不包含
     * @return [start, end) 范围的任意数字
     */
    @Contract(pure = true)
    static int range(int start, int end) {
        return gen().nextInt(start, end);
    }

    /**
     * 随机数字
     *
     * @param start 开始范围, 包含
     * @param end   结束范围, 包含
     * @return [start, end] 范围内的任意数字
     */
    @Contract(pure = true)
    static int rangeClosed(int start, int end) {
        return gen().nextInt(start, end + 1);
    }

    /**
     * 随机数字
     *
     * @param start 开始范围, 包含
     * @param end   结束范围, 不包含
     * @return [start, end) 范围的任意数字
     */
    @Contract(pure = true)
    static long range(long start, long end) {
        return gen().nextLong(start, end);
    }

    /**
     * 随机数字
     *
     * @param start 开始范围, 包含
     * @param end   结束范围, 包含
     * @return [start, end] 范围内的任意数字
     */
    @Contract(pure = true)
    static long rangeClosed(long start, long end) {
        return gen().nextLong(start, end + 1);
    }

}
